#!/usr/bin/env sh

set -ex

function pull_repo()
{
    echo "Deleting old repo: "$2
    rm -rf $2
    mkdir -p $2
    curl -L -o repo.zip $1
	unzip repo.zip -d $2
	mv $2/$3/* $2/ && rm -rf $2/$3
	rm -rf repo.zip
}

SPEEX_FORK=https://github.com/xiph/speex/archive/refs/tags/Speex-1.2.1.zip
SPEEX_LOCAL_REPO=./extra/speex
SPEEX_BRANCH=speex-Speex-1.2.1

function build_speex() 
{
    echo "===== Building speex libraries begin ====="
    cd $REPO
    pull_repo $SPEEX_FORK $SPEEX_LOCAL_REPO $SPEEX_BRANCH
    cd buildscripts
    pwd
    rm -rf build/thirdparty/mac/include/speex
    mv ../extra/speex/include/speex build/thirdparty/mac/include
    rm -rf ../extra/speex

    cd -

    echo "===== Building speex libraries end ====="
}

DAV1D_FORK=https://code.videolan.org/videolan/dav1d/-/archive/1.5.1/dav1d-1.5.1.zip
DAV1D_LOCAL_REPO=./extra/dav1d
DAV1D_BRANCH=dav1d-1.5.1

function fetch_dav1d() 
{
    echo "===== Fetching dav1d libraries begin ====="
    cd $REPO
    pull_repo $DAV1D_FORK $DAV1D_LOCAL_REPO $DAV1D_BRANCH

    echo "===== Fetching dav1d libraries end ====="
}

function build_ffmpeg()
{
    echo "===== Building FFmpeg libraries on $1 ====="

    set +x
    export COMMON_FF_CFG_FLAGS=
    source buildscripts/ff_config_mac_lv.sh
    set -x

    [ -d extra/ffmpeg-$1 ] || mkdir extra/ffmpeg-$1

    cd extra/ffmpeg-$1

    export PKG_CONFIG_PATH=$REPO/buildscripts/build/thirdparty/mac/lib/pkgconfig:$PKG_CONFIG_PATH
    export PATH=$PKG_CONFIG_PATH:$PATH
    echo $PATH

    if [[ `uname -m` == $1 ]]; then
        FF_CROSS_BUILD=""
    else
        FF_CROSS_BUILD="--enable-cross-compile"
    fi

    echo "start configure"
    MACOSX_DEPLOYMENT_TARGET=10.13 $REPO/configure \
        --arch=$1 \
        --prefix=$REPO/build/ffmpeg-$1 \
        --extra-cflags="-target $1-apple-macos -mmacosx-version-min=10.13 -I$REPO/buildscripts/build/thirdparty/mac/include/" \
        --extra-ldflags="-target $1-apple-macos -mmacosx-version-min=10.13 -L$REPO/buildscripts/build/thirdparty/mac/lib/ -framework CoreVideo -framework Metal -framework MetalPerformanceShaders" \
        $FF_CROSS_BUILD \
        $COMMON_FF_CFG_FLAGS \

    make -j8
    make install

    cd -

    # delete symbolic files
    cd $REPO/build/ffmpeg-$1/lib
    for lib in `find *.dylib -type l`; do
        rm $lib
    done

    # change install_name with @rpath prefix
    for lib in `ls -1 *.dylib`; do
        name=$(otool -D $lib | grep -oE "lib[a-z0-9.]+dylib$" | grep -oE "lib[a-z0-9]+").dylib
        install_name_tool -id @rpath/$name $lib
        mv $lib $name
    done

    # change dependent libraries to new install_name
    for lib in `ls -1 *.dylib`; do
        for dep in $(otool -L $lib | grep -oE "^.+/ffmpeg-$1/lib/lib\S+\.dylib"); do
            name=$(echo $dep | grep -oE "lib[a-z0-9.]+dylib$" | grep -oE "lib[a-z0-9]+").dylib
            install_name_tool -change $dep @rpath/$name $lib
        done
    done

    # #split the DSYM File
    # for lib in `ls -1 *.dylib`; do
    #     dsymutil $lib
    # done

    cd -

    echo "===== Building FFmpeg libraries on $1 end ====="
}

function build_libvecryptor()
{
    echo "===== Building libvecrptor on $1 ====="

    cd $REPO/libvecrptor

    clang++ -g \
    -std=c++14 \
    -mmacosx-version-min=10.13 -target $1-apple-macos \
    -I $REPO -I $REPO/libvecrptor -I $REPO/build/ffmpeg-$1/include \
    -c *.cpp

    clang++ -dynamiclib \
    -fPIC -shared \
    -current_version 1.0.0 \
    -compatibility_version 1.0.0 \
    -install_name @rpath/libvecryptor.dylib \
    -mmacosx-version-min=10.13 -target $1-apple-macos \
    -L $REPO/build/ffmpeg-$1/lib \
    -lavformat \
    -lavutil \
    *.o \
    -o $REPO/build/ffmpeg-$1/lib/libvecryptor.dylib

    rm *.o

    cd -

    echo "===== Building crptor libraries on $1 end ====="
}

function build_libffmpeg()
{
    echo "===== Building libFFmpeg on $1 ====="

    [ -d extra/ffmpeg-$1/libffmpeg ] && rm -rf extra/ffmpeg-$1/libffmpeg || echo
    mkdir -p extra/ffmpeg-$1/libffmpeg
    cd extra/ffmpeg-$1/libffmpeg

    has_err=""

    clang -g \
    -fvisibility=hidden \
    -mmacosx-version-min=10.13 -target $1-apple-macos \
    -I .. -I $REPO -I $REPO/libffmpeg \
	-c \
	$REPO/libffmpeg/*.c \
    || has_err="YES"

    clang -dynamiclib \
    -current_version 1.0.0 \
    -compatibility_version 1.0.0 \
    -install_name @rpath/libffmpeg.dylib \
    -mmacosx-version-min=10.13 -target $1-apple-macos \
    -L $REPO/build/ffmpeg-$1/lib \
    -lavformat \
    -lavcodec \
    -lavfilter \
    -lavutil \
    -lswresample \
    -lavdevice \
    -lswscale \
    -lvecryptor \
    -framework CoreFoundation \
    -framework CoreVideo \
    -framework CoreServices \
    -o $REPO/build/ffmpeg-$1/lib/libffmpeg.dylib \
    *.o \
    || has_err="YES"

    if [[ -n "$has_err" ]]; then
        echo "Error: failed to compile libffmpeg"
        cd -
        return -1
    fi

    # copy header file
    [ -d $REPO/build/ffmpeg-$1/include/libffmpeg ] || mkdir $REPO/build/ffmpeg-$1/include/libffmpeg
    cp $REPO/libffmpeg/ffmpeg_main.h $REPO/build/ffmpeg-$1/include/libffmpeg

    cd -

    echo "===== Building libFFmpeg on $1 end ====="
}

function build_ffmpeg_program()
{
    echo "===== Building FFmpeg Program on $1 ====="

    [ -d build/ffmpeg-$1/bin ] && rm -rf build/ffmpeg-$1/bin || echo
    mkdir build/ffmpeg-$1/bin

    [ -d extra/ffmpeg-$1/bin ] && rm -rf extra/ffmpeg-$1/bin || echo
    mkdir -p extra/ffmpeg-$1/bin
    cd extra/ffmpeg-$1/bin

    stat=""

    clang -g \
        -fvisibility=hidden \
        -mmacosx-version-min=10.13 -target $1-apple-macos \
        -I.. -I$REPO -I$REPO/fftools/ \
        -c \
        $REPO/fftools/ffmpeg.c $REPO/fftools/cmdutils.c $REPO/fftools/ffmpeg_opt.c \
        $REPO/fftools/ffmpeg_filter.c $REPO/fftools/ffmpeg_hw.c $REPO/fftools/proxy.c \
        $REPO/fftools/opt_common.c $REPO/fftools/ffmpeg_sched.c $REPO/fftools/ffmpeg_dec.c\
        $REPO/fftools/ffmpeg_mux.c $REPO/fftools/ffmpeg_demux.c $REPO/fftools/ffmpeg_mux_init.c\
        $REPO/fftools/ffmpeg_enc.c $REPO/fftools/thread_queue.c $REPO/fftools/sync_queue.c\
        $REPO/fftools/objpool.c\
        || stat="Compile Failed"

    clang -Wall \
        -o $REPO/build/ffmpeg-$1/bin/ffmpeg \
        -mmacosx-version-min=10.13 \
        -target $1-apple-macos \
        -rpath @loader_path/../lib \
        -rpath @loader_path/../Frameworks \
        -L$REPO/buildscripts/build/thirdparty/mac/lib/ \
        -L$REPO/build/ffmpeg-$1/lib \
        -ldav1d \
        -lavcodec \
        -lavdevice \
        -lavfilter \
        -lavformat \
        -lavutil \
        -lffmpeg \
        -lswresample \
        -lswscale \
        -lvecryptor \
        -lz -lbz2 -liconv \
        -framework AudioToolbox \
        -framework Cocoa \
        -framework CoreGraphics \
        -framework CoreImage \
        -framework OpenGL \
        -framework CoreMedia \
        -framework CoreVideo \
        -framework VideoToolbox \
        *.o \
        || stat="Link Failed"
        
    if [[ -z "$stat" ]]; then
        echo "===== Building FFmpeg Program on $1 End ====="
        cd -
    else
        echo "===== Error: failed to compile ffmpeg program on $1 ====="
        cd -
        return -1
    fi
}

function install()
{
    echo "===== Installing ====="

    FIRST_ARCH=$(echo $1 | grep -oE "^[^;]+")
    ARCH_LIST=$(echo $1 | grep -Eo "[^;]+")
    HAS_ARM64=$(echo $ARCH_LIST | grep -o "arm64" || true)
    HAS_X86_64=$(echo $ARCH_LIST | grep -o "x86_64" || true)

    [ -d dist/mac ] && rm -rf dist/mac || echo
    mkdir -p dist/mac/bin dist/mac/ dist/mac/lib

    echo "===== Installing: Copy FFmpeg program ====="
    if [[ -n $HAS_ARM64 && -n $HAS_X86_64 ]]; then
        lipo build/ffmpeg-x86_64/bin/ffmpeg build/ffmpeg-arm64/bin/ffmpeg -create -output dist/mac/bin/ffmpeg
    else
        cp -v build/ffmpeg-$FIRST_ARCH/bin/ffmpeg dist/mac/bin/ffmpeg
    fi
    lipo -info dist/mac/bin/ffmpeg
    dsymutil dist/mac/bin/ffmpeg

    echo "===== Installing: Copy FFmpeg headers ====="
    cp -vR build/ffmpeg-$FIRST_ARCH/include dist/mac/

    echo "===== Installing: Copy FFmpeg internal headers ====="
    [ -d dist/mac/include/internal ] && rm -rf dist/mac/include/internal || echo

    mkdir -p dist/mac/include/internal
    cp extra/ffmpeg-$FIRST_ARCH/config.h dist/mac/include/internal
    if [[ -n $HAS_X86_64 ]]; then
        mkdir -p dist/mac/include/internal/x86_64
        cp extra/ffmpeg-x86_64/config.h dist/mac/include/internal/x86_64
    fi
    if [[ -n $HAS_ARM64 ]]; then
        mkdir -p dist/mac/include/internal/arm64
        cp extra/ffmpeg-arm64/config.h dist/mac/include/internal/arm64
    fi

    cp extra_include/config.h dist/mac/include/internal/config.h
    mkdir -p dist/mac/include/internal/libavcodec
    cp libavcodec/bytestream.h dist/mac/include/internal/libavcodec/bytestream.h
    cp libavcodec/h264.h dist/mac/include/internal/libavcodec/h264.h
    cp libavcodec/h2645_parse_ve.h dist/mac/include/internal/libavcodec/h2645_parse_ve.h
    cp libavcodec/vt_internal.h dist/mac/include/internal/libavcodec/vt_internal.h
    cp libavcodec/internal.h dist/mac/include/internal/libavcodec/internal.h
    cp libavcodec/packet_internal.h dist/mac/include/internal/libavcodec/packet_internal.h

    mkdir -p dist/mac/include/internal/libavformat
    cp libavformat/dv.h dist/mac/include/internal/libavformat/dv.h
    cp libavformat/internal.h dist/mac/include/internal/libavformat/internal.h
    cp libavformat/isom.h dist/mac/include/internal/libavformat/isom.h
    cp libavformat/os_support.h dist/mac/include/internal/libavformat/os_support.h
    cp libavformat/mux.h dist/mac/include/internal/libavformat/mux.h

    mkdir -p dist/mac/include/internal/libavutil
    cp libavutil/reverse.h dist/mac/include/internal/libavutil/reverse.h
    cp libavutil/internal.h dist/mac/include/internal/libavutil/internal.h
    cp libavutil/attributes_internal.h dist/mac/include/internal/libavutil/attributes_internal.h
    cp libavutil/timer.h dist/mac/include/internal/libavutil/timer.h
    cp libavutil/libm.h dist/mac/include/internal/libavutil/libm.h
    cp libavutil/intmath.h dist/mac/include/internal/libavutil/intmath.h
    cp libavutil/mem_internal.h dist/mac/include/internal/libavutil/mem_internal.h
	cp libavutil/getenv_utf8.h dist/mac/include/internal/libavutil/getenv_utf8.h

    cp libavcodec/get_bits.h dist/mac/include/libavcodec/get_bits.h
    cp libavcodec/mathops.h dist/mac/include/libavcodec/mathops.h
    cp libavcodec/vlc.h dist/mac/include/libavcodec/vlc.h
    cp libavcodec/thread.h dist/mac/include/libavcodec/thread.h
    cp libavcodec/golomb.h dist/mac/include/libavcodec/golomb.h
    cp libavcodec/put_bits.h dist/mac/include/libavcodec/put_bits.h
    cp libavcodec/rnd_avg.h dist/mac/include/libavcodec/rnd_avg.h
    cp libavcodec/hevcpred.h dist/mac/include/libavcodec/hevcpred.h
    cp libavcodec/hevcdec.h dist/mac/include/libavcodec/hevcdec.h
    cp libavcodec/dovi_rpu.h dist/mac/include/libavcodec/dovi_rpu.h
    cp libavcodec/h274.h dist/mac/include/libavcodec/h274.h
    cp libavcodec/threadframe.h dist/mac/include/libavcodec/threadframe.h
    cp libavcodec/bswapdsp.h dist/mac/include/libavcodec/bswapdsp.h
    cp libavcodec/cabac.h dist/mac/include/libavcodec/cabac.h
    cp libavcodec/h2645_parse.h dist/mac/include/libavcodec/h2645_parse.h
    cp libavcodec/hevc.h dist/mac/include/libavcodec/hevc.h
    cp libavcodec/hevc_ps.h dist/mac/include/libavcodec/hevc_ps.h
    cp libavcodec/hevcdsp.h dist/mac/include/libavcodec/hevcdsp.h
    cp libavcodec/h2645_vui.h dist/mac/include/libavcodec/h2645_vui.h
    cp libavcodec/h2645_sei.h dist/mac/include/libavcodec/h2645_sei.h
    cp libavcodec/aom_film_grain.h dist/mac/include/libavcodec/aom_film_grain.h
	cp libavcodec/codec_internal.h dist/mac/include/libavcodec/codec_internal.h
    cp libavcodec/videodsp.h dist/mac/include/libavcodec/videodsp.h
    cp libavcodec/hevc_parse.h dist/mac/include/libavcodec/hevc_parse.h
    cp libavcodec/hevc_data.h dist/mac/include/libavcodec/hevc_data.h
    cp libavcodec/hevc_sei.h dist/mac/include/libavcodec/hevc_sei.h
    cp libavcodec/sei.h dist/mac/include/libavcodec/sei.h
    cp libavcodec/parser.h dist/mac/include/libavcodec/parser.h
	cp libavcodec/refstruct.h dist/mac/include/libavcodec/refstruct.h
	cp libavcodec/decode.h dist/mac/include/libavcodec/decode.h

    #######################################################x86    
    mkdir -p dist/mac/include/internal/libavutil/x86
    mkdir -p dist/mac/include/libavutil/x86/
    cp libavutil/x86/timer.h dist/mac/include/internal/libavutil/x86/timer.h   
    cp libavutil/x86/intmath.h dist/mac/include/libavutil/x86/intmath.h

    mkdir -p dist/mac/include/libavcodec/x86
    cp libavcodec/x86/mathops.h dist/mac/include/libavcodec/x86/mathops.h
    cp libavutil/x86/asm.h dist/mac/include/libavutil/x86/asm.h

    #######################################################arm
    mkdir -p dist/mac/include/internal/libavutil/arm
    #cp libavutil/arm/timer.h dist/mac/include/internal/libavutil/arm/timer.h   

    mkdir -p dist/mac/include/libavcodec/arm
    #cp libavcodec/arm/mathops.h dist/mac/include/libavcodec/arm/mathops.h

    mkdir -p dist/mac/include/libavutil/arm
    #cp libavutil/arm/intmath.h dist/mac/include/libavutil/arm/intmath.h

    #######################################################x86    
    mkdir -p dist/mac/include/internal/libavutil/aarch64
    cp libavutil/aarch64/timer.h dist/mac/include/internal/libavutil/aarch64/timer.h   

    mkdir -p dist/mac/include/libavcodec/aarch64

    mkdir -p dist/mac/include/libavutil/aarch64

    echo "===== Installing: Copy dynamic libraries ====="
    cp -vR buildscripts/build/thirdparty/mac/lib/*.dylib dist/mac/lib/
    if [[ -n $HAS_ARM64 && -n $HAS_X86_64 ]]; then
        for dfile in $(find build/ffmpeg-x86_64/lib/*.dylib -type f); do
            dname="${dfile##*/}"
            lipo build/ffmpeg-{arm64,x86_64}/lib/$dname -create -output dist/mac/lib/$dname
        done
    elif [[ -n $HAS_X86_64 ]]; then
        cp build/ffmpeg-x86_64/lib/*.dylib dist/mac/lib/
    elif [[ -n $HAS_ARM64 ]]; then
        cp build/ffmpeg-arm64/lib/*.dylib dist/mac/lib/
    else
        echo "Error: none of library"
    fi

    dsymutil  dist/mac/lib/*.dylib
}

if [[ -z $1 ]]; then
    ARCH_LIST=`uname -m`  # use native arch by default
elif [[ $1 == "all" ]]; then
    ARCH_LIST="x86_64;arm64"
else
    ARCH_LIST=$1
fi

REPO=$(git rev-parse --show-toplevel)

pod ipc spec CCFFmpegMac.podspec | awk '/^\{/{f=1} f' > CCFFmpegMac.podspec.json

build_speex
fetch_dav1d

for ARCH in $(echo $ARCH_LIST | grep -Eo "[^;]+"); do
    cd $REPO

    build_ffmpeg $ARCH

    build_libvecryptor $ARCH

    build_libffmpeg $ARCH

    build_ffmpeg_program $ARCH

    echo "===== Building $ARCH success. ====="
done

install $ARCH_LIST

cp -rf $REPO/dist/mac ./output

echo "===== Building ends, all success ====="
